package com.smallstep.hystrix.command;

import com.netflix.hystrix.HystrixCommand;
import com.smallstep.hystrix.entity.FFFallbackMethod;
import com.smallstep.hystrix.entity.FFRequestInfo;
import com.smallstep.hystrix.enums.HystrixKeyEnum;
import com.smallstep.hystrix.enums.ReturnModeEnum;
import com.smallstep.hystrix.properties.FFHystrixProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author 李俊
 */
public abstract class FFHystrixCommand <T> extends HystrixCommand<T> {
    private static final Logger LOGGER = LoggerFactory.getLogger(FFHystrixCommand.class);
    private FFRequestInfo requestInfo;
    private FFFallbackMethod fallbackMethod;

    protected FFHystrixCommand(FFRequestInfo requestInfo, FFFallbackMethod fallbackMethod) {
        super(requestInfo.toHystrixSetting(fallbackMethod));
        this.requestInfo = requestInfo;
        this.fallbackMethod = fallbackMethod;
    }
    @Override
    protected T getFallback() {
        this.log();
        Object result;
        if (this.fallbackMethod == null) {
            result = super.getFallback();
        } else {
            result = this.callMethod(this.fallbackMethod.getMethod(), this.fallbackMethod.getBean());
        }

        if (this.requestInfo.getReturnMode().equals(ReturnModeEnum.RESPONSE_ENTITY) && !(result instanceof ResponseEntity)) {
            result = new ResponseEntity(result, HttpStatus.OK);
        } else if (!this.requestInfo.getReturnMode().equals(ReturnModeEnum.RESPONSE_ENTITY) && result instanceof ResponseEntity) {
            result = ((ResponseEntity)result).getBody();
        }

        return (T) result;
    }

    /**
     *
     */
    private void log() {
        boolean isLog = false;
        if (this.isFailedExecution() && FFHystrixProperties.getPropertyForBoolean(HystrixKeyEnum.FF_HYSTRIX_CLIENT_LOG_FAILED_EXECUTION_ENABLED)) {
            isLog = true;
        } else if (this.isResponseTimedOut() && FFHystrixProperties.getPropertyForBoolean(HystrixKeyEnum.FF_HYSTRIX_CLIENT_LOG_TIMEOUT_ENABLED)) {
            isLog = true;
        } else if (this.isResponseShortCircuited() && FFHystrixProperties.getPropertyForBoolean(HystrixKeyEnum.FF_HYSTRIX_CLIENT_LOG_SHORT_CIRCUIT_ENABLED)) {
            isLog = true;
        } else if (this.isResponseRejected() && FFHystrixProperties.getPropertyForBoolean(HystrixKeyEnum.FF_HYSTRIX_CLIENT_LOG_REJECTION_ENABLED)) {
            isLog = true;
        }

        if (isLog) {
            LOGGER.error("error on [" + this.requestInfo.getMethod() + " " + this.requestInfo.getUrl() + "]", this.getExecutionException());
        }

    }

    private Object callMethod(Method method, Object bean) {
        Boolean accessible = method.isAccessible();

        try {
            Class[] parameterTypes = method.getParameterTypes();
            Object[] args = new Object[parameterTypes.length];

            for(int i = 0; i < args.length; ++i) {

            }

            method.setAccessible(true);
            Object var14 = method.invoke(bean, args);
            return var14;
        } catch (IllegalAccessException var11) {

        } catch (InvocationTargetException var12) {

        } finally {
            method.setAccessible(accessible);
        }

        return null;
    }
}
